package m

import (
	"GameServer/Common/utils"
	"fmt"
	"sync"

	"github.com/globalsign/mgo/bson"
	log "github.com/sirupsen/logrus"

	"GameServer/Common/data"
	"GameServer/Game/cache"
	"GameServer/Game/dbmodule"
	"GameServer/Game/errors"
)

type UnionIco struct {
	Bottom string
	Pic    string
}

// 公会
type Union struct {
	BaseM
	Id             bson.ObjectId `bson:"_id" json:"id"`
	Name           string        `bson:"name" json:"name"`
	Ico            *UnionIco     `bson:"ico,omitempty" json:"ico"`
	Score          int64         `bson:"score" json:"score"`
	Desc           string        `bson:"desc" json:"desc"`
	JoinStatus     int64         `bson:"joinStatus" json:"joinStatus"`
	Num            int64         `bson:"num" json:"num"` // 公会总人数
	ShortName      string        `bson:"shortName" json:"shortName"`
	Star           int64         `bson:"star" json:"star"`
	StarChangeTime int64         `bson:"starChangeTime" json:"starChangeTime"` // 星星改变时间
	CreateTime     int64         `bson:"createTime" json:"createTime"`         // 工会创建时间
}

// 成员信息
type UnionMember struct {
	Uid         string `bson:"uid" json:"uid"`
	Name        string `bson:"name" json:"name"`
	Head        string `bson:"head" json:"head"`
	Score       int64  `bson:"score" json:"score"`
	JoinTime    int64  `bson:"joinTime" json:"joinTime"`
	Manager     int64  `bson:"manager" json:"manager"`
	Star        int64  `bson:"star" json:"star"`
	OffLineTime int64  `bson:"offLineTime" json:"offLineTime"`
	AvatarFrame int64  `bson:"avatarFrame" json:"avatarFrame"`
	onLine      int64
}

// 公会成员
type UnionMembers struct {
	BaseM
	UnionId bson.ObjectId           `bson:"_id" json:"id"`
	Members map[string]*UnionMember `bson:"members,omitempty" json:"members"`
	rw      *sync.RWMutex
}

func NewUnion() cache.EntryI {
	return new(Union)
}

func (u *Union) Save() (err error) {
	err = dbmodule.MgoDB.GameDB.Upsert("union", bson.M{"_id": u.Id}, u)
	if err != nil {
		return
	}
	return
}

func (u *Union) Load(key interface{}) (err error) {
	switch key.(type) {
	case string:
		if key.(string) == "" {
			return errors.New("无效的key load, key empty")
		}
		u.Id = bson.ObjectIdHex(key.(string))
	case bson.ObjectId:
		u.Id = key.(bson.ObjectId)
	default:
		log.WithFields(log.Fields{
			"method": "Union_Load",
			"data":   key,
		}).Error("无效的key load")
		return errors.New("无效的key load")
	}
	return u.LoadData()
}

func (u *Union) LoadData() (err error) {
	err = dbmodule.MgoDB.GameDB.FindOne("union", bson.M{"_id": u.Id}, nil, &u)
	if err != nil {
		if err.Error() == "not found" {
			err = errors.NewErrcode(data.Errcode.NotFound, fmt.Sprintf("没有找到公会信息. id:%s", u.Id.Hex()))
			return
		}
		return
	}

	return
}

// 更新数据
func (u *Union) Update(val *Union) {
	Cache.Put("union", u.Id.Hex(), val)
	val.UpdateData()
}

func (u *Union) Delete() (err error) {
	Cache.Remove("union", u.Id.Hex())
	return dbmodule.MgoDB.GameDB.Remove("union", bson.M{"_id": u.Id})
}

func (u *Union) UpdateStar() (star int64) {
	v, ok := Cache.Get("unionMembers", u.Id.Hex())
	if !ok {
		return
	}
	defer u.Update(u)
	v1 := v.(*UnionMembers)
	u.StarChangeTime = utils.TNow().Unix()
	u.Star = v1.GetAllStar()
	return u.Star
}

func NewUnionMembers() cache.EntryI {
	return &UnionMembers{Members: make(map[string]*UnionMember, 0), rw: new(sync.RWMutex)}
}

func (um *UnionMembers) Save() (err error) {
	err = dbmodule.MgoDB.GameDB.Upsert("unionMembers", bson.M{"_id": um.UnionId}, um)
	if err != nil {
		return
	}
	return
}

func (um *UnionMembers) Load(key interface{}) (err error) {
	switch key.(type) {
	case string:
		um.UnionId = bson.ObjectIdHex(key.(string))
	case bson.ObjectId:
		um.UnionId = key.(bson.ObjectId)
	default:
		log.WithFields(log.Fields{
			"method": "UnionMembers_Load",
			"data":   key,
		}).Error("无效的key load")
		return errors.New("无效的key load")
	}
	return um.LoadData()
}

func (um *UnionMembers) LoadData() (err error) {
	err = dbmodule.MgoDB.GameDB.FindOne("unionMembers", bson.M{"_id": um.UnionId}, nil, &um)
	if err != nil {
		return
	}
	return
}

// 更新数据
func (um *UnionMembers) Update(val *UnionMembers) {
	Cache.Put("unionMembers", val.UnionId.Hex(), val)
	val.UpdateData()
}

func (um *UnionMembers) Delete() (err error) {
	Cache.Remove("unionMembers", um.UnionId)
	return dbmodule.MgoDB.GameDB.Remove("unionMembers", bson.M{"_id": um.UnionId})
}

func (um *UnionMembers) RWLock() *sync.RWMutex {
	if um.rw == nil {
		um.rw = new(sync.RWMutex)
	}
	return um.rw
}

func (um *UnionMembers) GetMember(uid string) (r *UnionMember, ok bool) {
	um.RWLock().RLock()
	r, ok = um.Members[uid]
	um.RWLock().RUnlock()
	return
}

func (um *UnionMembers) AddMember(u *Union, uMember *UnionMember) (err error) {
	defer um.Update(um)
	um.RWLock().Lock()
	um.Members[uMember.Uid] = uMember
	u.Num = int64(len(um.Members)) // 统计公会人数
	um.RWLock().Unlock()

	u.Update(u) // 更新公会人数
	return
}

func (um *UnionMembers) MemberList() (r map[string]*UnionMember) {
	r = make(map[string]*UnionMember, 0)
	um.RWLock().RLock()
	for k, v := range um.Members {
		r[k] = v
	}
	um.RWLock().RUnlock()
	return r
}

func (um *UnionMembers) DelMember(u *Union, uid string) (err error) {
	um.RWLock().RLock()
	if _, ok := um.Members[uid]; ok {
		delete(um.Members, uid)
		u.Num = int64(len(um.Members))
		u.Update(u) // 更新公会人数

		um.Update(um) // 更新工会成员
	}
	um.RWLock().RUnlock()
	return
}

func (um *UnionMembers) GetTopMember() (top *UnionMember, err error) {
	um.RWLock().RLock()
	for _, v := range um.Members {
		if top == nil {
			top = v
			continue
		}
		if top.Score < v.Score {
			top = v
		}

	}
	um.RWLock().RUnlock()
	return
}

func (um *UnionMembers) GetAllStar() (star int64) {
	um.RWLock().RLock()
	defer um.RWLock().RUnlock()
	star = 0
	for _, item := range um.Members {
		star += item.Star
	}
	return
}

func (uMember *UnionMember) OffLine() {
	uMember.onLine = 0
	uMember.OffLineTime = utils.TNow().Unix()
}

func (uMember *UnionMember) OnLine() {
	uMember.onLine = 1
	uMember.OffLineTime = 0
}

func (uMember *UnionMember) OnLineVal() int64 {
	return uMember.onLine
}

// 禁止加入原来公会
type UnionBan struct {
	BaseM
	Uid       bson.ObjectId    `bson:"_id" json:"uid"`
	UnionBans map[string]int64 `bson:"unionBans" json:"unionBans"`
}

func NewUnionBan() cache.EntryI {
	return &UnionBan{UnionBans: make(map[string]int64, 0)}
}

func (u *UnionBan) Save() (err error) {
	err = dbmodule.MgoDB.GameDB.Upsert("unionBan", bson.M{"_id": u.Uid}, u)
	if err != nil {
		return
	}
	return
}

func (u *UnionBan) Load(key interface{}) (err error) {
	switch key.(type) {
	case string:
		if key.(string) == "" {
			return errors.New("无效的key load, key empty")
		}
		u.Uid = bson.ObjectIdHex(key.(string))
	case bson.ObjectId:
		u.Uid = key.(bson.ObjectId)
	default:
		log.WithFields(log.Fields{
			"method": "UnionBan_Load",
			"data":   key,
		}).Error("无效的key load")
		return errors.New("无效的key load")
	}
	return u.LoadData()
}

func (u *UnionBan) LoadData() (err error) {
	err = dbmodule.MgoDB.GameDB.FindOne("unionBan", bson.M{"_id": u.Uid}, nil, &u)
	if err != nil {
		if err.Error() == "not found" {
			return nil
		}
		return
	}
	return
}

// 更新数据
func (u *UnionBan) Update(val *UnionBan) {
	Cache.Put("unionBan", u.Uid.Hex(), val)
	val.UpdateData()
}

func (u *UnionBan) IsBan(unionId string) bool {
	if v, ok := u.UnionBans[unionId]; ok {
		return v > utils.TNow().Unix()
	}
	return false
}

func (u *UnionBan) AddUnionBan(unionId string) {
	defer u.Update(u)
	u.UnionBans[unionId] = utils.TNow().Unix() + 86400
}

func (u *UnionBan) ResetBansOutTime() {
	defer u.Update(u)
	for id, v := range u.UnionBans {
		if v < utils.TNow().Unix() {
			delete(u.UnionBans, id)
		}
	}
}

func (u *User) GetUnionBan() (r *UnionBan) {
	v, _ := Cache.Get("unionBan", u.Uid.Hex())
	r = v.(*UnionBan)
	r.ResetBansOutTime()
	return
}
